home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / strategy / colour-y.tgz / colour-y.tar / yahtzee / main.c < prev    next >
C/C++ Source or Header  |  1995-10-29  |  22KB  |  1,395 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <errno.h>
  6. #include <signal.h>
  7. #include <ncurses/ncurses.h>
  8. #include <stdarg.h>
  9. #include "yahtzee.h"
  10.  
  11. /*
  12.  * (c)1992 by orest zborowski
  13.  */
  14.  
  15. static char *header = "Yahtzee  Version 1.00  (c)1992 by zorst";
  16.  
  17. extern errno;
  18.  
  19. #define NUM_ROLLS 3
  20.  
  21. static char *upper_headers[NUM_UPPER] =
  22. {
  23.     "(a) 1 [total of 1s]",
  24.     "(b) 2 [total of 2s]",
  25.     "(c) 3 [total of 3s]",
  26.     "(d) 4 [total of 4s]",
  27.     "(e) 5 [total of 5s]",
  28.     "(f) 6 [total of 6s]"
  29. };
  30.  
  31. static char *lower_headers[NUM_LOWER] =
  32. {
  33.     "(g) 3 of a Knd [total]",
  34.     "(h) 4 of a Knd [total]",
  35.     "(i) Full House [25]",
  36.     "(j) Sm Straight [30]",
  37.     "(k) Lg Straight [40]",
  38.     "(l) Yahtzee [50]",
  39.     "(m) Chance [total]",
  40. };
  41.  
  42. int dice_values[5];
  43.  
  44. static char *dice[6][4] =
  45. {
  46.     "",
  47.     "     ",
  48.     "  o  ",
  49.     "     ",
  50.  
  51.     "",
  52.     "o    ",
  53.     "     ",
  54.     "    o",
  55.  
  56.     "",
  57.     "o    ",
  58.     "  o  ",
  59.     "    o",
  60.  
  61.     "",
  62.     "o   o",
  63.     "     ",
  64.     "o   o",
  65.  
  66.     "",
  67.     "o   o",
  68.     "  o  ",
  69.     "o   o",
  70.  
  71.     "",
  72.     "o   o",
  73.     "o   o",
  74.     "o   o",
  75. };
  76.  
  77. Player players[MAX_NUMBER_OF_PLAYERS];
  78.  
  79. int num_players;
  80.  
  81. static int longest_header;
  82.  
  83. int dodelay = 0;
  84.  
  85. int numlines;
  86.  
  87. init(void)
  88. {
  89.     int i;
  90.     int j;
  91.  
  92.     num_players = 0;
  93.  
  94.     srand(getpid());
  95.  
  96.     for (i = 0; i < MAX_NUMBER_OF_PLAYERS; ++i)
  97.     {
  98.         players[i].name[0] = '\0';
  99.         players[i].finished = 0;
  100.         players[i].comp = 0;
  101.  
  102.         for (j = 0; j < NUM_FIELDS; ++j)
  103.         {
  104.             players[i].score[j] = 0;
  105.             players[i].used[j] = 0;
  106.         }
  107.     }
  108.  
  109.     for (i = 0; i < NUM_UPPER; ++i)
  110.         if (strlen(upper_headers[i]) > longest_header)
  111.             longest_header = strlen(upper_headers[i]);
  112.  
  113.     for (i = 0; i < NUM_LOWER; ++i)
  114.         if (strlen(lower_headers[i]) > longest_header)
  115.             longest_header = strlen(lower_headers[i]);
  116.  
  117.     srand(getpid());
  118. }
  119.  
  120. static void fill_box(int x,int y, int h, int w)
  121. {
  122.     int dx,dy;
  123.     for(dy=y; dy<y+h; dy++)
  124.     {
  125.         for(dx=x;dx<x+w;dx++)
  126.         {
  127.             mvaddch(dx,dy,' ');
  128.         }
  129.     }
  130. }
  131.     
  132.  
  133. /*
  134. **    SCREEN ORGANIZATION:
  135. **        line 0:        version header
  136. **        line 1:        -----------
  137. **        line 2:        edit window
  138. **        line 3:        -----------
  139. **        line 4:        player names
  140. **        line 5-10    upper bank
  141. **        line 11:    upper total
  142. **        line 12:    Bonus
  143. **        line 13-19:    lower bank
  144. **        line 20:    lower total
  145. **        line 21:    total
  146. */
  147.  
  148. setup_screen(void)
  149. {
  150.     int i;
  151.  
  152.     initscr();
  153.     if (LINES < 23)
  154.         abort("Not enough lines on the terminal");
  155.     numlines = LINES;
  156.     
  157.     if(has_colors())
  158.     {
  159.         start_color();
  160.         init_pair(COLOR_WHITE, COLOR_BLACK, COLOR_WHITE);
  161.         init_pair(COLOR_GREEN, COLOR_BLACK, COLOR_GREEN);
  162.         init_pair(COLOR_YELLOW, COLOR_WHITE, COLOR_GREEN);
  163.         init_pair(COLOR_RED, COLOR_WHITE, COLOR_RED);
  164.     }
  165.     clear();
  166.     wattron(stdscr, COLOR_PAIR(COLOR_GREEN));
  167.     fill_box(0,0,COLS,LINES);
  168.     mvaddstr(0, 9, header);
  169.     move(1, 9);
  170.     for (i = 9; i < COLS; ++i)
  171.         addch(ACS_HLINE);
  172.     refresh();
  173. }
  174.  
  175. yend(void)
  176. {
  177.     attron(0);
  178.     move(0, 0);
  179.     clear();
  180.     refresh();
  181.     endwin();
  182. }
  183.  
  184. abort(char *msg)
  185. {
  186.     yend();
  187.     putchar('\n');
  188.     printf(msg);
  189.     putchar('\n');
  190.     exit(1);
  191. }
  192.  
  193. say(char *fmt, ...)
  194. {
  195.     va_list ap;
  196.     char buf[200];
  197.  
  198.     va_start(ap, fmt);
  199.     vsprintf(buf, fmt, ap);
  200.     va_end(ap);
  201.  
  202.     fill_box(2,10,COLS-10,1);
  203.     mvaddstr(2, 10, buf);
  204.     refresh();
  205. }
  206.  
  207. /*
  208. **    we have a trick in here - we will accept a '?' as the first character of
  209. **    a human answer.  in that case, we ask the computer for the die to roll
  210. **    or the place to put it.  then the human can decide what to do.
  211. */
  212. void
  213. query(int player, int question, char *prompt, char *ans, int len)
  214. {
  215.     int i;
  216.     char c;
  217.     int xpos;
  218.     char foo[2];
  219.  
  220.     xpos = 10 + strlen(prompt);
  221.     if (player >= 0 && players[player].comp)     /* for the computer */
  222.     {
  223.         fill_box(2,10,COLS-10,1);
  224.         mvaddstr(2, 10, prompt);
  225.         be_computer(player, question, ans, len);
  226.         mvaddstr(2, xpos, ans);
  227.         refresh();
  228.         if (dodelay)
  229.             sleep(COMPUTER_DELAY);        /* let person read it */
  230.         return;
  231.     }
  232.  
  233.     for (;;)
  234.     {
  235.         cbreak();
  236.         noecho();
  237.  
  238.         fill_box(2,10,COLS-10,1);
  239.         mvaddstr(2, 10, prompt);
  240.         refresh();
  241.  
  242.         i = 0;
  243.  
  244.         for (;;)
  245.         {
  246.             c = getch();
  247.             if (c == '\b' || c == 0x7f)
  248.             {
  249.                 if (i == 0)
  250.                     continue;
  251.                 --i;
  252.                 --xpos;
  253.                 mvaddch(2, xpos, ' ');
  254.                 move(2, xpos);
  255.             }
  256.  
  257.             else if (c == 10 || c == 13)
  258.                 break;
  259.  
  260.             else
  261.             {
  262.                 if (i == len)
  263.                     write(1, "\007", 1);
  264.  
  265.                 else
  266.                 {
  267.                     addch(c);
  268.                     ans[i] = c;
  269.                     ++xpos;
  270.                     ++i;
  271.                 }
  272.             }
  273.             refresh();
  274.         }
  275.  
  276.         ans[i] = '\0';
  277.  
  278.         echo();
  279.         nocbreak();
  280.  
  281.         if (ans[0] != '?')
  282.             break;
  283.  
  284. /*
  285. **    let the computer decide and then we can put that up for the human to
  286. **    read
  287. */
  288.         be_computer(player, question, ans, len);
  289.         query(-1, 0, ans, foo, sizeof(foo));
  290.     }
  291. }
  292.  
  293. int
  294. raw_roll_dice(void)
  295. {
  296.     return((rand() % 6) + 1);
  297. }
  298.  
  299. int
  300. roll_dice(int num)
  301. {
  302.     int val;
  303.     int i;
  304.     int j;
  305.  
  306.     if (num < 1 || num > 5)
  307.         abort("Bad dice loc passed");
  308.         
  309.     attron(COLOR_PAIR(COLOR_GREEN));
  310.  
  311.     for (j = 0; j < 1; ++j)
  312.     {
  313. /*
  314.         val = (random() % 6) + 1;
  315. */
  316.         val = raw_roll_dice();
  317.  
  318.         for (i = 0; i < 4; ++i)
  319.         {
  320.             move(((num - 1) * 4) + i, 0);
  321.  
  322.             if (i == 2)
  323.                 printw("%d", num);
  324.             else
  325.                 addch(' ');
  326.             attroff(COLOR_PAIR(COLOR_GREEN));
  327.             attron(COLOR_PAIR(COLOR_WHITE));
  328.             if(i==0)
  329.             {
  330.                 if(num==1)
  331.                     addch(ACS_ULCORNER);
  332.                 else
  333.                     addch(ACS_LTEE);
  334.                 addch(ACS_HLINE);
  335.                 addch(ACS_HLINE);
  336.                 addch(ACS_HLINE);
  337.                 addch(ACS_HLINE);
  338.                 addch(ACS_HLINE);
  339.                 if(num==1)
  340.                     addch(ACS_URCORNER);
  341.                 else
  342.                     addch(ACS_RTEE);
  343.             }
  344.             else
  345.             {
  346.                 addch(ACS_VLINE);
  347.                 addstr(dice[val - 1][i]);
  348.                 addch(ACS_VLINE);
  349.             }
  350.             attroff(COLOR_PAIR(COLOR_WHITE));
  351.             attron(COLOR_PAIR(COLOR_GREEN));
  352.         }
  353.  
  354.         if (num == 5)        /* put the last +---+ tail */
  355.         {
  356.             mvaddch(20, 0, ' ');
  357.             attroff(COLOR_PAIR(COLOR_GREEN));
  358.             attron(COLOR_PAIR(COLOR_WHITE));
  359.             addch(ACS_LLCORNER);
  360.             addch(ACS_HLINE);
  361.             addch(ACS_HLINE);
  362.             addch(ACS_HLINE);
  363.             addch(ACS_HLINE);
  364.             addch(ACS_HLINE);
  365.             addch(ACS_LRCORNER);
  366.             attroff(COLOR_PAIR(COLOR_WHITE));
  367.             attron(COLOR_PAIR(COLOR_GREEN));
  368.         }
  369.     }
  370.     refresh();
  371.     return (val);
  372. }
  373.  
  374. int
  375. upper_total(int num)
  376. {
  377.     int val;
  378.     int i;
  379.  
  380.     val = 0;
  381.  
  382.     for (i = 0; i < NUM_UPPER; ++i)
  383.         val += players[num].score[i];
  384.  
  385.     return (val);
  386. }
  387.  
  388. int
  389. lower_total(int num)
  390. {
  391.     int val;
  392.     int i;
  393.  
  394.     val = 0;
  395.  
  396.     for (i = 0; i < NUM_LOWER; ++i)
  397.         val += players[num].score[i + NUM_UPPER];
  398.  
  399.     return (val);
  400. }
  401.  
  402. int
  403. total_score(int num)
  404. {
  405.     int upper_tot;
  406.     int lower_tot;
  407.     int i;
  408.  
  409.     upper_tot = 0;
  410.     lower_tot = 0;
  411.  
  412.     lower_tot = lower_total(num);
  413.     upper_tot = upper_total(num);
  414.  
  415.     if (upper_tot >= 63)
  416.         upper_tot += 35;
  417.  
  418.     return (upper_tot + lower_tot);
  419. }
  420.  
  421. void
  422. show_player(int num, int field)
  423. {
  424.     int i;
  425.     int line;
  426.     int upper_tot;
  427.     int lower_tot;
  428.     int xpos;
  429.  
  430.     xpos = 10 + longest_header + (num * MAX_NAME_LENGTH);
  431.  
  432.     for (i = 0; i < NUM_FIELDS; ++i)
  433.     {
  434.         if (i == field || field == -1)
  435.         {
  436.             line = 5 + i;
  437.  
  438.             if (i >= NUM_UPPER)
  439.                 line += 2;
  440.  
  441.             move(line, xpos);
  442.  
  443.             if (players[num].used[i])
  444.                 printw(" %4d", players[num].score[i]);
  445.  
  446.             else
  447.                 addstr("     ");
  448.         }
  449.     }
  450.  
  451.     upper_tot = upper_total(num);
  452.     lower_tot = lower_total(num);
  453.  
  454.     move(12, xpos);
  455.  
  456.     if (upper_tot >= 63)
  457.     {
  458.         printw("+%4d", 35);
  459.         upper_tot += 35;
  460.     }
  461.     else
  462.         addstr("    ");
  463.  
  464.     mvprintw(11, xpos, "(%4d)", upper_tot);
  465.     mvprintw(20, xpos, "(%4d)", lower_tot);
  466.     mvprintw(21, xpos, "[%4d]", upper_tot + lower_tot);
  467.  
  468.     refresh();
  469. }
  470.  
  471. void
  472. setup_board(void)
  473. {
  474.     int i;
  475.     int j;
  476.  
  477.     move(3, 9);
  478.     for (i = 9; i < COLS; ++i)
  479.         addch(ACS_HLINE);
  480.  
  481.     for (i = 0; i < NUM_UPPER; ++i)
  482.         mvaddstr(i+5, 9, upper_headers[i]);
  483.  
  484.     move(11, 9);
  485.     attron(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
  486.     addstr(" Upper Total");
  487.     move(12, 9);
  488.     addstr(" Bonus");
  489.     attroff(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
  490.     attron(COLOR_PAIR(COLOR_GREEN));
  491.  
  492.     for (i = 0; i < NUM_LOWER; ++i)
  493.         mvaddstr(i+13, 9, lower_headers[i]);
  494.  
  495.     move(20, 9);
  496.     attron(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
  497.     addstr(" Lower Total");
  498.     move(21, 9);
  499.     addstr(" Grand Total");
  500.     attroff(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
  501.     attron(COLOR_PAIR(COLOR_GREEN));
  502.  
  503.     for (j = 0; j < num_players; ++j)
  504.     {
  505.         for (i = 4; i < 22; ++i)
  506.             mvaddch(i, 9 + longest_header + (j * MAX_NAME_LENGTH),
  507.                 ACS_VLINE);
  508.     }
  509.  
  510.     for (i = 0; i < num_players; ++i)
  511.     {
  512.         mvaddstr(4, 10 + longest_header + (i * MAX_NAME_LENGTH),
  513.              players[i].name);
  514.         show_player(i, -1);
  515.     }
  516.  
  517.     refresh();
  518. }
  519.  
  520. int
  521. count(int val)
  522. {
  523.     int i;
  524.     int num;
  525.  
  526.     num = 0;
  527.  
  528.     for (i = 0; i < 5; ++i)
  529.         if (dice_values[i] == val)
  530.             ++num;
  531.  
  532.     return (num);
  533. }
  534.  
  535. int
  536. find_n_of_a_kind(int n, int but_not)
  537. {
  538.     int val;
  539.     int i;
  540.     int j;
  541.  
  542.     for (i = 0; i < 5; ++i)
  543.     {
  544.         if (dice_values[i] == but_not)
  545.             continue;
  546.  
  547.         if (count(dice_values[i]) >= n)
  548.             return (dice_values[i]);
  549.     }
  550.  
  551.     return (0);
  552. }
  553.  
  554. int
  555. find_straight(int run, int notstart, int notrun)
  556. {
  557.     int i;
  558.     int j;
  559.  
  560.     for (i = 1; i < 7; ++i)
  561.     {
  562.         if (i >= notstart && i < notstart + notrun)
  563.             continue;
  564.  
  565.         for (j = 0; j < run; ++j)
  566.             if (!count(i + j))
  567.                 break;
  568.  
  569.         if (j == run)
  570.             return (i);
  571.     }
  572.  
  573.     return (0);
  574. }
  575.  
  576. int
  577. find_yahtzee(void)
  578. {
  579.     int i;
  580.  
  581.     for (i = 1; i < 7; ++i)
  582.         if (count(i) == 5)
  583.             return (i);
  584.  
  585.     return (0);
  586. }
  587.  
  588. int
  589. add_dice(void)
  590. {
  591.     int i;
  592.     int val;
  593.  
  594.     val = 0;
  595.  
  596.     for (i = 0; i < 5; ++i)
  597.         val += dice_values[i];
  598.  
  599.     return (val);
  600. }
  601.  
  602. int
  603. showoff(int p, short so)
  604. {
  605.     move(4, 10 + longest_header + (p * MAX_NAME_LENGTH));
  606.  
  607.     if (so)
  608.     {
  609.         attroff(COLOR_PAIR(COLOR_GREEN));
  610.         attron(A_STANDOUT);
  611.     }
  612.     else
  613.         attron(COLOR_PAIR(COLOR_GREEN));
  614.  
  615.     addstr(players[p].name);
  616.  
  617.     if (so)
  618.     {
  619.         attroff(A_STANDOUT);
  620.         attron(COLOR_PAIR(COLOR_GREEN));
  621.     }
  622.     refresh();
  623. }
  624.  
  625. void
  626. handle_play(int player)
  627. {
  628.     int i;
  629.     char buf[50];
  630.     char *cp;
  631.     char *num;
  632.     int done;
  633.     int field;
  634.     int dummy;
  635.     int numroll;
  636.  
  637.     if (players[player].finished)    /* all finished */
  638.         return;
  639.  
  640.     showoff(player, 1);
  641.  
  642.     say("Rolling for %s", players[player].name);
  643.  
  644.     for (i = 1; i < 6; ++i)
  645.         dice_values[i - 1] = roll_dice(i);
  646.  
  647.     for (numroll = 1; numroll < NUM_ROLLS; ++numroll)
  648.     {
  649.         query(player, 1, "What dice to roll again (<RETURN> for none)? ",
  650.           buf, sizeof(buf));
  651.  
  652.         cp = buf;
  653.         if (*cp == '\0')
  654.             break;
  655.  
  656.         done = 0;
  657.  
  658.         for (;;)
  659.         {
  660.             num = cp;
  661.             while (*cp != '\0' && *cp != ',' && *cp != '\t' && *cp != ' ')
  662.                 ++cp;
  663.             if (*cp == '\0')
  664.                 done = 1;
  665.             *cp++ = '\0';
  666.             i = atoi(num);
  667.             if (i >= 1 && i <= 5)
  668.                 dice_values[i - 1] = roll_dice(i);
  669.             if (done)
  670.                 break;
  671.         }
  672.     }
  673.  
  674.     query(player, 2, "Where do you want to put that? ", buf, sizeof(buf));
  675.     done = 0;
  676.  
  677.     for (;;)
  678.     {
  679.         if (buf[0] < 'a' || buf[0] > 'm')
  680.         {
  681.             query(player, 2, "No good! Where do you want to put that? ",
  682.               buf, sizeof(buf));
  683.             continue;
  684.         }
  685.  
  686.         field = buf[0] - 'a';
  687.  
  688.         switch(field)
  689.         {
  690.             case 0:
  691.             case 1:
  692.             case 2:
  693.             case 3:
  694.             case 4:
  695.             case 5:
  696.                 if (players[player].used[field])
  697.                 {
  698.                     query(player, 2, "Already used! Where do you want to put that? ",
  699.                       buf, sizeof(buf));
  700.  
  701.                     break;
  702.                 }
  703.  
  704.                 players[player].used[field] = 1;
  705.  
  706.                 players[player].score[field] =
  707.                   count(field + 1) * (field + 1);
  708.  
  709.                 done = 1;
  710.  
  711.                 show_player(player, field);
  712.  
  713.                 break;
  714.  
  715.             case 6:
  716.                 if (players[player].used[field])
  717.                 {
  718.                     query(player, 2, "Already used! Where do you want to put that? ",
  719.                       buf, sizeof(buf));
  720.  
  721.                     break;
  722.                 }
  723.  
  724.                 players[player].used[field] = 1;
  725.  
  726.                 if (find_n_of_a_kind(3, 0))
  727.                     players[player].score[field] =
  728.                       add_dice();
  729.  
  730.                 show_player(player, field);
  731.  
  732.                 done = 1;
  733.  
  734.                 break;
  735.  
  736.             case 7:
  737.                 if (players[player].used[field])
  738.                 {
  739.                     query(player, 2, "Already used! Where do you want to put that? ",
  740.                       buf, sizeof(buf));
  741.  
  742.                     break;
  743.                 }
  744.  
  745.                 players[player].used[field] = 1;
  746.  
  747.                 if (find_n_of_a_kind(4, 0))
  748.                     players[player].score[field] =
  749.                       add_dice();
  750.  
  751.                 show_player(player, field);
  752.  
  753.                 done = 1;
  754.  
  755.                 break;
  756.  
  757.             case 8:
  758.                 if (players[player].used[field])
  759.                 {
  760.                     query(player, 2, "Already used! Where do you want to put that? ",
  761.                       buf, sizeof(buf));
  762.  
  763.                     break;
  764.                 }
  765.  
  766.                 players[player].used[field] = 1;
  767.  
  768.                 dummy = find_n_of_a_kind(3, 0);
  769.  
  770.                 if (dummy != 0)
  771.                 {
  772.                     if (find_n_of_a_kind(2, dummy))
  773.                         players[player].score[field] =
  774.                           25;
  775.                 }
  776.  
  777.                 show_player(player, field);
  778.  
  779.                 done = 1;
  780.  
  781.                 break;
  782.  
  783.             case 9:
  784.                 if (players[player].used[field])
  785.                 {
  786.                     query(player, 2, "Already used! Where do you want to put that? ",
  787.                       buf, sizeof(buf));
  788.  
  789.                     break;
  790.                 }
  791.  
  792.                 players[player].used[field] = 1;
  793.  
  794.                 if (find_straight(4, 0, 0))
  795.                     players[player].score[field] = 30;
  796.  
  797.                 show_player(player, field);
  798.  
  799.                 done = 1;
  800.  
  801.                 break;
  802.  
  803.             case 10:
  804.                 if (players[player].used[field])
  805.                 {
  806.                     query(player, 2, "Already used! Where do you want to put that? ",
  807.                       buf, sizeof(buf));
  808.  
  809.                     break;
  810.                 }
  811.  
  812.                 players[player].used[field] = 1;
  813.  
  814.                 if (find_straight(5, 0, 0))
  815.                     players[player].score[field] = 40;
  816.  
  817.                 show_player(player, field);
  818.  
  819.                 done = 1;
  820.  
  821.                 break;
  822.  
  823.             case 11:
  824. /*
  825. **    if the player scratched, the score for that field will be 0.
  826. **    in that case, we don't allow it to be used any more.
  827. */
  828.                 if ((players[player].score[field] == 0 ||
  829.                   !find_yahtzee()) &&
  830.                   players[player].used[field] == 1)
  831.                 {
  832.                     query(player, 2, "Already used! (he he) Where do you want to put that? ",
  833.                       buf, sizeof(buf));
  834.  
  835.                     break;
  836.                 }
  837.  
  838.                 if (find_yahtzee())
  839.                     players[player].score[field] += 50;
  840.  
  841.                 players[player].used[field] = 1;
  842.  
  843.                 show_player(player, field);
  844.  
  845.                 done = 1;
  846.  
  847.                 break;
  848.  
  849.             case 12:
  850.                 if (players[player].used[field])
  851.                 {
  852.                     query(player, 2, "Already used! Where do you want to put that? ",
  853.                       buf, sizeof(buf));
  854.  
  855.                     break;
  856.                 }
  857.  
  858.                 players[player].used[field] = 1;
  859.  
  860.                 players[player].score[field] = add_dice();
  861.  
  862.                 show_player(player, field);
  863.  
  864.                 done = 1;
  865.  
  866.                 break;
  867.         }
  868.  
  869.         if (done)
  870.             break;
  871.     }
  872.  
  873.     showoff(player, 0);
  874.  
  875.     for (i = 0; i < NUM_FIELDS; ++i)
  876.         if (!players[player].used[i])
  877.             return;
  878.  
  879.     players[player].finished = 1;
  880. }
  881.  
  882. void
  883. play(void)
  884. {
  885.     int i;
  886.     int topscore;
  887.     int winner;
  888.  
  889.     for (;;)
  890.     {
  891.         for (i = 0; i < num_players; ++i)
  892.             handle_play(i);
  893.  
  894.         for (i = 0; i < num_players; ++i)
  895.             if (!players[i].finished)
  896.                 break;
  897.  
  898.         if (i == num_players)
  899.             break;
  900.     }
  901.  
  902.     topscore = -1;
  903.  
  904.     for (i = 0; i < num_players; ++i)
  905.         if (total_score(i) > topscore)
  906.         {
  907.             topscore = total_score(i);
  908.  
  909.             winner = i;
  910.         }
  911.  
  912.     say("The winner is %s", players[winner].name);
  913. }
  914.  
  915. #define L_LOCK 0
  916. #define L_UNLOCK 1
  917.  
  918. void
  919. lock(char *fname, int type)
  920. {
  921.     char lockfile[200];
  922.     struct stat statbuf;
  923.     int i;
  924.     FILE *fp;
  925.  
  926.     strcpy(lockfile, fname);
  927.  
  928.     strcat(lockfile, ".L");
  929.  
  930.     if (type == L_LOCK)
  931.     {
  932.         for (i = 1; ;++i)
  933.         {
  934.             stat(lockfile, &statbuf);
  935.  
  936.             if (errno == ENOENT)
  937.                 break;
  938.  
  939.             say("Waiting for lock... (%d)", i);
  940.  
  941.             sleep(1);
  942.         }
  943.  
  944.         fp = fopen(lockfile, "w");
  945.  
  946.         fclose(fp);
  947.     }
  948.  
  949.     else
  950.     {
  951.         unlink(lockfile);
  952.     }
  953. }
  954.  
  955. static int
  956. write_score(FILE *fp, char *name, char *date, int score)
  957. {
  958.     return fprintf(fp, "%s\001%s\001%d\n", name, date, score);
  959. }
  960.  
  961. static int
  962. read_score(FILE *fp, char *name, char *date, int *score)
  963. {
  964.     char buf[200];
  965.     char *sb, *se;
  966.  
  967.     if (!fgets(buf, sizeof(buf), fp))
  968.         return -1;
  969.     if (!(se = strchr(buf, '\001')))
  970.         return -1;
  971.     *se++ = '\0';
  972.     strcpy(name, buf);
  973.     if ((sb = se) > buf + sizeof(buf))
  974.         return -1;
  975.     if (!(se = strchr(sb, '\001')))
  976.         return -1;
  977.     *se++ = '\0';
  978.     strcpy(date, sb);
  979.     if ((sb = se) > buf + sizeof(buf))
  980.         return -1;
  981.     if (!(se = strchr(sb, '\n')))
  982.         return -1;
  983.     *se = '\0';
  984.     *score = atoi(sb);
  985.     return 0;
  986. }
  987.  
  988. /*
  989. **    we keep track of the top nnn persons.
  990. */
  991. void
  992. update_scorefile(void)
  993. {
  994.     FILE *fp;
  995.     FILE *tp;
  996.     char scorefile[200];
  997.     char tmpfile[100];
  998.     int numtop;
  999.     int nump;
  1000.     int j;
  1001.     char name[20];
  1002.     char date[30];
  1003.     char *curdate;
  1004.     int score;
  1005.     int topscore;
  1006.     int tmptop;
  1007.     long clock;
  1008.     char scall[100];
  1009.  
  1010.     sprintf(tmpfile, "%s/y.%x", SCOREDIR, getpid());
  1011.     sprintf(scorefile, "%s/%s", SCOREDIR, SCOREFNAME);
  1012.  
  1013.     clock = time(0);
  1014.  
  1015.     curdate = (char *) ctime(&clock);
  1016.  
  1017.     if (strchr(curdate, '\n'))
  1018.         *strchr(curdate, '\n') = '\0';
  1019.  
  1020.     if ((tp = fopen(tmpfile, "w")) == NULL)
  1021.     {
  1022.         say("Can't update score file.");
  1023.         return;
  1024.     }
  1025.  
  1026.     lock(scorefile, L_LOCK);
  1027.  
  1028.     fp = fopen(scorefile, "r");
  1029.  
  1030.     for (j = 0; j < num_players; ++j)
  1031.         players[j].finished = -1;
  1032.  
  1033.     numtop = 0;
  1034.     nump = 0;
  1035.     topscore = 99999;
  1036.  
  1037.     for (;;)
  1038.     {
  1039. /*
  1040. **    get the next entry from the score file.  if there isn't any, then
  1041. **    we set the score to beat to -99 (everyone playing can beat it)
  1042. */
  1043.         if (fp == NULL || read_score(fp, name, date, &score))
  1044.             score = -99;
  1045.  
  1046. /*
  1047. **    now, we search through all players to find out which ones have scores
  1048. **    higher than the one read (but less than topscore).  these will get
  1049. **    saved before the read entry does. now, we only do this if all players
  1050. **    haven't been accounted for.
  1051. */
  1052.         for (; nump != num_players;)
  1053.         {
  1054.             tmptop = -99;
  1055.  
  1056.             for (j = 0; j < num_players; ++j)
  1057.                 if (total_score(j) > tmptop &&
  1058.                   total_score(j) < topscore)
  1059.                 {
  1060.                     tmptop = total_score(j);
  1061.                 }
  1062.  
  1063.             if (tmptop == -99)    /* everybody better */
  1064.                 break;
  1065.  
  1066.             if (tmptop > score)
  1067.             {
  1068.                 topscore = tmptop;
  1069.  
  1070.                 for (j = 0; j < num_players; ++j)
  1071.                     if (total_score(j) == tmptop)
  1072.                     {
  1073.                         if (numtop >= NUM_TOP_PLAYERS)
  1074.                             break;
  1075.  
  1076.                         write_score(tp,
  1077.                           players[j].name, curdate,
  1078.                           tmptop);
  1079.  
  1080.                         players[j].finished = numtop;
  1081.  
  1082.                         ++nump;
  1083.  
  1084.                         ++numtop;
  1085.                     }
  1086.             }
  1087.  
  1088.             else
  1089.                 break;
  1090.         }
  1091.  
  1092.         if (score != -99 && numtop < NUM_TOP_PLAYERS)
  1093.         {
  1094.             write_score(tp, name, date, score);
  1095.             ++numtop;
  1096.         }
  1097. /*
  1098. **    if we processed all top slots or processed all players (and there
  1099. **    was no score to beat), we stop.
  1100. */
  1101.         if (numtop == NUM_TOP_PLAYERS ||
  1102.           (nump == num_players && score == -99))
  1103.             break;
  1104.     }
  1105.  
  1106.     fclose(tp);
  1107.     if (fp)
  1108.         fclose(fp);
  1109.  
  1110. #ifdef HAS_RENAME
  1111.     if (rename(tmpfile, scorefile))
  1112.     {
  1113.         say("rename failed!");
  1114.         unlink(tmpfile);
  1115.     }
  1116. #else
  1117.     sprintf(scall, "mv %s %s", tmpfile, scorefile);
  1118.     system(scall);
  1119. #endif
  1120.  
  1121.     lock(scorefile, L_UNLOCK);
  1122. }
  1123.  
  1124. void
  1125. show_top_scores(void)
  1126. {
  1127.     FILE *fp;
  1128.     char scorefile[200];
  1129.     int i, j, k, score;
  1130.     char stuff[1024];
  1131.     char name[32], date[32];
  1132.     
  1133.     attron(COLOR_PAIR(COLOR_RED));
  1134.     fill_box(0,0,COLS,LINES);
  1135.     attroff(COLOR_PAIR(COLOR_RED));
  1136.     attron(COLOR_PAIR(COLOR_WHITE));
  1137.     fill_box(0,0,COLS,1);
  1138.     move(0,(COLS-strlen("Yahtzee Top Scores"))/2); 
  1139.     addstr("Yahtzee Top Scores");
  1140.     attroff(COLOR_PAIR(COLOR_WHITE));
  1141.  
  1142.     sprintf(scorefile, "%s/%s", SCOREDIR, SCOREFNAME);
  1143.  
  1144.     if ((fp = fopen(scorefile, "r")) == NULL)
  1145.     {
  1146.         yend();
  1147.         printf("Can't get at score file.\n");
  1148.         return;
  1149.     }
  1150.  
  1151.     j = 0;
  1152.     attron(COLOR_PAIR(COLOR_RED));
  1153.  
  1154.     for (i = 0; i < NUM_TOP_PLAYERS; ++i)
  1155.     {
  1156.         if (read_score(fp, name, date, &score))
  1157.             break;
  1158.  
  1159.         if (j >= numlines - 4)
  1160.         {
  1161.             move(23,(COLS-strlen("<Hit Return>"))/2);
  1162.             addstr("<Hit Return>");
  1163.             refresh();
  1164.             getch();
  1165.             j = 0;
  1166.         }
  1167.  
  1168.         for (k = 0; k < num_players; ++k)
  1169.             if (players[k].finished == i)
  1170.                 break;
  1171.         fill_box(j+3,4,COLS-4,1);
  1172.         move(j+3,4);
  1173.         sprintf(stuff,"%3d : %-10s %s %d", i + 1, name, date, score);
  1174.         addstr(stuff);
  1175.         ++j;
  1176.     }
  1177.  
  1178.     fclose(fp);
  1179.     move(23,(COLS-strlen("<Hit Return>"))/2);
  1180.     addstr("<Hit Return>");
  1181.     refresh();
  1182.     getch();
  1183.     yend();
  1184. }
  1185.  
  1186. void
  1187. calc_random(void)
  1188. {
  1189.     char nrollstr[10];
  1190.     int nroll;
  1191.     int table[NUM_FIELDS];
  1192.     int i;
  1193.     int j;
  1194.  
  1195.     printf ("How many times to you wish to roll? ");
  1196.  
  1197.     gets(nrollstr);
  1198.     nroll = atoi(nrollstr);
  1199.  
  1200.     printf("Generating...\n");
  1201.  
  1202.     for (i = 0; i < NUM_FIELDS; ++i)
  1203.         table[i] = 0;
  1204.  
  1205.     for (i = 0; i < nroll; ++i)
  1206.     {
  1207.         for (j = 0; j < 5; ++j)
  1208.             dice_values[j] = raw_roll_dice();
  1209.  
  1210.         for (j = 1; j <= 6; ++j)
  1211.             if (count(j) > 0)
  1212.                 ++table[j-1];
  1213.  
  1214.         if (find_n_of_a_kind(3, 0))
  1215.             ++table[6];
  1216.  
  1217.         if (find_n_of_a_kind(4, 0))
  1218.             ++table[7];
  1219.  
  1220.         j = find_n_of_a_kind(3, 0);
  1221.  
  1222.         if (j != 0 && find_n_of_a_kind(2, j))
  1223.             ++table[8];
  1224.  
  1225.         if (find_straight(4, 0, 0))
  1226.             ++table[9];
  1227.  
  1228.         if (find_straight(5, 0, 0))
  1229.             ++table[10];
  1230.  
  1231.         if (find_yahtzee())
  1232.             ++table[11];
  1233.     }
  1234.  
  1235.     printf("%-35s %10s %20s\n", "Results:", "Num Rolls", "Total");
  1236.  
  1237.     for (i = 0; i < NUM_FIELDS; ++i)
  1238.     {
  1239.         if (i < NUM_UPPER)
  1240.             printf("%-35s", upper_headers[i]);
  1241.  
  1242.         else
  1243.             printf("%-35s", lower_headers[i-NUM_UPPER]);
  1244.  
  1245.         printf(" %10d %20d\n", table[i],
  1246.           (long) (table[i] * 100) / nroll);
  1247.     }
  1248. }
  1249.  
  1250. void
  1251. signal_trap()
  1252. {
  1253.     yend();
  1254.     exit(0);
  1255. }
  1256.  
  1257. set_signal_traps()
  1258. {
  1259.     signal(SIGHUP, signal_trap);
  1260.     signal(SIGINT, signal_trap);
  1261.     signal(SIGQUIT, signal_trap);
  1262. }
  1263.  
  1264. main(int argc, char **argv)
  1265. {
  1266.     char num[10];
  1267.     int i;
  1268.     int num_computers;
  1269.     short onlyshowscores = 0;
  1270.  
  1271.     while (--argc > 0)
  1272.     {
  1273.         if ((*++argv)[0] == '-')
  1274.         {
  1275.             switch ((*argv)[1])
  1276.             {
  1277.                 case 's':
  1278.                     onlyshowscores = 1;
  1279.                     break;
  1280.  
  1281.                 case 'n':
  1282.                     printf("obsolete function - delay turned off by default.\n");
  1283.                     break;
  1284.  
  1285.                 case 'd':
  1286.                     dodelay = 1;
  1287.                     break;
  1288.  
  1289.                 case 'r':
  1290.                     calc_random();
  1291.                     exit(0);
  1292.  
  1293.                 default:
  1294.                     printf("usage: yahtzee [-s] [-d] [-r]\n");
  1295.                     printf("\t-s\tonly show scores\n");
  1296.                     printf("\t-d\tcomputer move delay\n");
  1297.                     printf("\t-r\tcalculate random die throws (debug)\n");
  1298.                     exit(0);
  1299.             }
  1300.         }
  1301.     }
  1302.  
  1303.     if (!onlyshowscores)
  1304.     {
  1305.         printf("\n\nWelcome to the game of Yahtzee...\n\n");
  1306.  
  1307.         init();
  1308.  
  1309.         do
  1310.         {
  1311.             printf("How many wish to play (max of %d)? ",
  1312.               MAX_NUMBER_OF_PLAYERS);
  1313.             fflush(stdout);
  1314.  
  1315.             fgets(num, 10, stdin);
  1316.  
  1317.             if (strchr(num, '\n'))
  1318.                 *strchr(num, '\n') = '\0';
  1319.  
  1320.             num_players = atoi(num);
  1321.  
  1322.             if (num_players == 0)
  1323.                 break;
  1324.         }
  1325.         while (num_players < 1 || num_players > MAX_NUMBER_OF_PLAYERS);
  1326.  
  1327.         for (i = 0; i < num_players; ++i)
  1328.         {
  1329.             printf("What is the name of player #%d ? ", i + 1);
  1330.             fflush(stdout);
  1331.  
  1332.             fgets(players[i].name, MAX_NAME_LENGTH, stdin);
  1333.  
  1334.             if (strchr(players[i].name, '\n'))
  1335.                 *strchr(players[i].name, '\n') = '\0';
  1336.         }
  1337.  
  1338.         if (num_players == MAX_NUMBER_OF_PLAYERS)
  1339.         {
  1340.             printf("Boo hoo... I can't play...\n");
  1341.         }
  1342.  
  1343.         else
  1344.         {
  1345.             do
  1346.             {
  1347.                 printf("How many computers to play (max of %d) ? ",
  1348.                   MAX_NUMBER_OF_PLAYERS - num_players);
  1349.                 fflush(stdout);
  1350.  
  1351.                 fgets(num, sizeof(num), stdin);
  1352.  
  1353.                 num_computers = atoi(num);
  1354.             }
  1355.             while (num_computers < 0 ||
  1356.               num_players + num_computers > MAX_NUMBER_OF_PLAYERS);
  1357.  
  1358.             for (i = 0; i < num_computers; ++i)
  1359.             {
  1360.                 players[num_players].comp = 1;
  1361.  
  1362.                 sprintf(players[num_players].name, "Mr. %c",
  1363.                   i + 'A');
  1364.  
  1365.                 ++num_players;
  1366.             }
  1367.         }
  1368.  
  1369.         if (num_players == 0)
  1370.         {
  1371.             printf("Well, why did you run this anyways???\n\n");
  1372.  
  1373.             exit(8);
  1374.         }
  1375.     }
  1376.  
  1377.     setup_screen();
  1378.  
  1379.     set_signal_traps();
  1380.  
  1381.     if (!onlyshowscores)
  1382.     {
  1383.         setup_board();
  1384.  
  1385.         play();
  1386.  
  1387.         update_scorefile();
  1388.     }
  1389.  
  1390.     getch();
  1391.     show_top_scores();
  1392.  
  1393.     exit(0);
  1394. }
  1395.